package com.cs.service.impl;

import com.cs.domain.*;
import com.cs.domain.vo.*;
import com.cs.mapper.CSProcurementPlanMapper;
import com.cs.mapper.CsTenderMapper;
import com.cs.service.CSCodeRulesService;
import com.cs.service.CSProcurementPlanService;
import com.cs.service.NonTenderProjectService;
import com.cs.util.CSRuleCode;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.security.utils.SecurityUtils;
import com.ruoyi.system.api.domain.SysUser;
import com.ruoyi.system.api.model.LoginUser;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static com.cs.util.CSRuleCreate.createCode;
import static java.util.concurrent.CompletableFuture.runAsync;

/**
 * @Author：bbdf
 * @Package：com.cs.service.impl
 * @Project：RuoYi-Cloud
 * @name：CSProcurementPlanServiceImpl
 * @Date：2024-11-12 14:15
 * @Filename：CSProcurementPlanServiceImpl
 */
@Service
public class CSProcurementPlanServiceImpl implements CSProcurementPlanService {
    @Autowired
    private CSProcurementPlanMapper csProcurementPlanMapper;
    @Autowired
    private CSCodeRulesService service;
    @Autowired
    private RedissonClient redissonClient;
    @Autowired
    private CsTenderMapper tenderMapper;
    @Autowired
    private NonTenderProjectService nonTenderProjectService;

    @Override
    public List<CSProcurementPlan> getPlanList(CSProcurementPlan plan) {
        return csProcurementPlanMapper.getPlanList(plan);
    }

    @Override
    public String getBudgetCode() {
        return this.createCodeWithLock();
    }

    private String createCodeWithLock() {
        Long threadId = Thread.currentThread().getId()+SecurityUtils.getLoginUser().getUserid();
        RLock lock = redissonClient.getLock(threadId.toString());
        try {
//            尝试获取锁，最多等待3秒，锁有效期为2秒
            if (lock.tryLock(3, 2, TimeUnit.SECONDS))
                return createCode(service, "cs_budget").getCode();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } finally {
            if (lock.isHeldByCurrentThread()) {
                // 释放锁
                lock.unlock();
            }
        }
        return null;
    }

    @Override
    @Transactional
    public Integer addPurchasePlan(PurchasePlanVO formPlan) {
        String planCode = createCode(service, CSRuleCode.PROCUREMENTNAME).getCode();//采购计划Code
        //CSBudgetVO赋予code值及采购计划code
        CompletableFuture.supplyAsync(() -> {
            List<CSBudgetVO> collect = formPlan.getBudgetList().stream().map(s -> {
                s.setDuId(s.getDuId());
                s.setaId(planCode);
                return s;
            }).collect(Collectors.toList());
            Integer res = csProcurementPlanMapper.addBudgetList(collect);
            if (res <= 0) {
                throw new RuntimeException("添加失败");
            } else {
                return collect;
            }
        });


        //行项目
        List<CSLineItems> collect = formPlan.getDeviceList().stream().map(s -> {
            CSLineItems lineItems = new CSLineItems();
            String code = createCode(service, CSRuleCode.LINEPROJECT).getCode();//行项目Code
            lineItems.setvCode(code);
            lineItems.setaId(planCode);
            lineItems.settId(s.gettId());
            lineItems.setvCount(s.getvCount());
            lineItems.setvPerson(s.getvPerson());
            lineItems.setvDeliveryTime(s.getvDeliveryTime());
            lineItems.setvDeliveryArea(s.getvDeliveryArea());
            lineItems.setvIllustrate(s.getvIllustrate());
            lineItems.setdId(s.getaId());//这里的aId是前端搞错了原本是duCode(dId)
            return lineItems;
        }).toList();
        csProcurementPlanMapper.addLineItems(collect);
        //获取登录用户
        LoginUser loginUser = SecurityUtils.getLoginUser();

        CSProcurementPlan plans = new CSProcurementPlan();
        plans.setCreateBy(loginUser.getUsername());
        plans.setDeptId(Integer.valueOf(loginUser.getSysUser().getDeptId().toString()));
        plans.setUpdateBy(loginUser.getUsername());
        plans.setaName(formPlan.getPlan().getaName());
        plans.setaCode(planCode);
        plans.setProjectCount(formPlan.getDeviceList().size());
        plans.setTypeId(formPlan.getPlan().getTypeId());
        plans.setAstate(1);
        //新增计划
        Integer integer = csProcurementPlanMapper.addPlan(plans);
        runAsync(() -> {
            List<File> files = formPlan.getPlan().getFileList();
            System.out.println("files.size() = " + files.size());
            if (files.size() > 0) {
                List<CSPubAttachments> collect1 = files.stream().map(s -> {
                    CSPubAttachments csPubAttachments = new CSPubAttachments();
                    csPubAttachments.setaCode(planCode);
                    csPubAttachments.setCreateBy(loginUser.getUsername());
                    csPubAttachments.setUpdateBy(loginUser.getUsername());
                    csPubAttachments.setAnSize(s.getSize());
                    csPubAttachments.setAnName(s.getName());
                    return csPubAttachments;
                }).toList();
                csProcurementPlanMapper.addPubFile(collect1);
            }
        });
        return integer;
    }


    @Override
    public PurchasePlanVO getPurchasePlanByACode(String aCode) {
        //基本信息(附件查询)
        CompletableFuture<CSProcurementPlanVO> planInfo = CompletableFuture.supplyAsync(() -> {
            CSProcurementPlanVO csProcurementPlanVO = csProcurementPlanMapper.getPlanInfoByACode(aCode);//不合规操作
            return csProcurementPlanVO;
        });

        //采购预算
        CompletableFuture<List<CSBudgetVO>> budgetInfo = CompletableFuture.supplyAsync(() -> {
            List<CSBudgetVO> csBudgetVOList = csProcurementPlanMapper.getProcurementInfo(aCode);//不合规操作
            return csBudgetVOList;
        });

        //行项目
        List<CSLineItemsVO> csLineItemsVOS = csProcurementPlanMapper.getLineItems(aCode);//不合规操作

        CSProcurementPlanVO csProcurementPlanVO = null;
        List<CSBudgetVO> csBudgetVOList = null;
        try {
            csProcurementPlanVO = planInfo.get();
            csBudgetVOList = budgetInfo.get();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } catch (ExecutionException e) {
            throw new RuntimeException(e);
        }

        PurchasePlanVO purchasePlanVO = new PurchasePlanVO();
        purchasePlanVO.setPlan(csProcurementPlanVO);
        purchasePlanVO.setBudgetList(csBudgetVOList);
        purchasePlanVO.setDeviceList(csLineItemsVOS);
        return purchasePlanVO;
    }

    @Override
    public List<CSProcurementPlanVO> getPlanByState(String aCode) {
        return csProcurementPlanMapper.getPlanByState(aCode);
    }
    @Override
    @Transactional
    public Integer editPlan(PurchasePlanVO plan) {
        //行项目
        List<String> strings = plan.getDeviceList().stream().map(s -> s.getvCode()).toList();
        runAsync(() -> {
            csProcurementPlanMapper.deleteLineItems(strings);
            List<CSLineItems> collect = plan.getDeviceList().stream().map(s -> {
                CSLineItems lineItems = new CSLineItems();
                if ("".equals(s.getvCode())||s.getvCode()==null){
                    lineItems.setvCode(createCode(service, CSRuleCode.LINEPROJECT).getCode());
                }else {
                    lineItems.setvCode(s.getvCode());
                }
                lineItems.setaId(plan.getPlan().getaCode());
                lineItems.settId(s.gettId());
                lineItems.setvCount(s.getvCount());
                lineItems.setvPerson(s.getvPerson());
                lineItems.setvDeliveryTime(s.getvDeliveryTime());
                lineItems.setvDeliveryArea(s.getvDeliveryArea());
                lineItems.setvIllustrate(s.getvIllustrate());
                lineItems.setdId(s.getdId());
                return lineItems;
            }).toList();
            csProcurementPlanMapper.addLineItems(collect);
        });

        //预算
        List<String> strings1 = plan.getBudgetList().stream().map(s -> s.getDuId()).toList();
        csProcurementPlanMapper.deleteBudget(strings1);
        List<CSBudgetVO> csBudgetVOList = plan.getBudgetList().stream().map(s -> {
            s.setaId(plan.getPlan().getaCode());
            return s;
        }).toList();
        csProcurementPlanMapper.addBudgetList(csBudgetVOList);

        //基础信息
        String username = SecurityUtils.getLoginUser().getUsername();
        plan.getPlan().setUpdateBy(username);
        plan.getPlan().setProjectCount(plan.getDeviceList().size());
        csProcurementPlanMapper.updatePlan(plan.getPlan());

        //附件
        CompletableFuture.runAsync(()-> {
            csProcurementPlanMapper.deleteFile(plan.getPlan().getaCode());
            List<File> files = plan.getPlan().getFileList();
            if (files.size() > 0) {
                List<CSPubAttachments> collect1 = files.stream().map(s -> {
                    System.out.println(s+"非典事件卡迪夫黑科技");
                    CSPubAttachments csPubAttachments = new CSPubAttachments();
                    csPubAttachments.setaCode(plan.getPlan().getaCode());
                    csPubAttachments.setAnSize(s.getSize());
                    csPubAttachments.setAnUrl(s.getUrl());
                    csPubAttachments.setAnName(s.getName());
                    return csPubAttachments;
                }).toList();
                csProcurementPlanMapper.addPubFile(collect1);
            }
        });
            return 1;
    }


    @Override
    public Integer deleteDevice(String vCode){
        return  csProcurementPlanMapper.deleteLineItem(vCode);
    }

    @Override
    public Integer changeAstateByACode(CSProcurementPlanVO plan) {
        if (plan.getAstate()==3){
            LoginUser loginUser = SecurityUtils.getLoginUser();
            String username = loginUser.getUsername();
            plan.setProcessedBy(username);
            plan.setDeptId(plan.getpDeptId());
            plan.setpTime(new Date());
        }
        return csProcurementPlanMapper.changeAstateByACode(plan);
    }

    @Override
    @Transactional
    public R<Integer> submitSourcing(SourcingVO sourcingVO, List<SysUser> sysUsers) {
        //更改采购计划状态为 4 (已寻源)
        List<CSProcurementPlan> planList = sourcingVO.getPlan().stream().map(s -> {
            s.setAstate(4);
            return s;
        }).toList();
        if (csProcurementPlanMapper.updatePlanAstate(planList)<0){
            return R.fail("失败");
        }
        //判断是招标或是非招标
        Integer type = sourcingVO.getType();
        LoginUser loginUser = SecurityUtils.getLoginUser();
        if(type==1||type==6){
            //异步创建采购招标项目
            CompletableFuture.runAsync(()->{
                List<CsTender> csTenders = sourcingVO.getPlan().stream()
                        .map(s -> {
                           Double total=csProcurementPlanMapper.getBudgetTotal(s.getaCode());
                            CsTender tender = new CsTender();
                            tender.setiNumber(createCode(service, CSRuleCode.INVITETENDERS).getCode());
                            tender.setXyId(s.getaCode());
                            Optional<String> any = sysUsers.stream()
                                    .filter(y -> s.getCreateBy().equals(y.getUserName()))
                                    .map(y -> y.getDept().getLeader())
                                    .findAny();
                            any.ifPresent(tender::setpLeader);
                            tender.setiWay(Long.parseLong(sourcingVO.getType().toString()));
                            tender.setbType(Long.parseLong(s.getTypeId().toString()));
                            tender.setCreateBy(loginUser.getUsername());
                            tender.setiName(s.getaName());
                            tender.setpBudget(BigDecimal.valueOf(total));
                            tender.setProjectState(Long.parseLong(1+""));
                            return tender;
                        })
                        .toList();
                int i = tenderMapper.insertListCsTender(csTenders);
            });
        }else{
            //异步创建采购非招标项目
            CompletableFuture.runAsync(()->{
                List<NonTenderProject> nonTenderProjects = sourcingVO.getPlan().stream()
                        .map(s -> {
//                            Double total=csProcurementPlanMapper.getBudgetTotal(s.getaCode());
                            NonTenderProject non = new NonTenderProject();
                            non.setXyId(s.getaCode());
                            non.setgCode(createCode(service, CSRuleCode.NOTINVITETENDERS).getCode());
                            non.setgName(s.getaName());
                            non.setgSpawnTime(new Date());
                            non.setgTenderType(s.getTypeId());
                            non.setgNotes(s.getOpinion());
//                            non.set
                            return non;
                        }).toList();
                nonTenderProjectService.createNonTenderPro(nonTenderProjects);
            });
        }
        return R.ok(1,"寻源成功");
    }

    @Override
    public List<CSProcurementPlan> getNotSourcing(CSProcurementPlan plan) {
        return csProcurementPlanMapper.getNotSourcing(plan);
    }

    @Override
    public List<TenderNeedLineItemsVO> getTenderNeedLineItems(String xyId) {
        return csProcurementPlanMapper.getTenderNeedLineItems(xyId);
    }

    @Override
    public Integer addNoticeFile(List<CSPubAttachments> csPubAttachments1) {
        return csProcurementPlanMapper.addNoticeFile(csPubAttachments1);
    }

    @Override
    public int selectCSProcurementPlanCount(CSProcurementPlan state) {
        return csProcurementPlanMapper.selectCSProcurementPlanCount(state);
    }

    @Override
    public Integer editBudgetForm(CSBudget state) {
        return csProcurementPlanMapper.editBudgetForm(state);
    }


    @Override
    public Integer deleteBudgetForm(String duId) {
        return csProcurementPlanMapper.deleteBudgetForm(duId);
    }

    @Override
    public List<CSLineItemsVO> getLineItemsList(String iNumber) {
        return csProcurementPlanMapper.getLineItemsList(iNumber);
    }
}
